package com.iot.server.service.impl;

import com.google.common.collect.Maps;
import com.iot.core.annotation.DictName;
import com.iot.core.domain.BaseDO;
import com.iot.core.exception.BDException;
import com.iot.core.utils.ListUtils;
import com.iot.server.dao.SysDictDOMapper;
import com.iot.server.domain.SelectDO;
import com.iot.server.domain.SysDictDO;
import com.iot.server.service.DictService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author wuzt
 * Date 2019/10/12 14:18
 * Version 1.0
 * @ClassName DictServiceImpl
 * Description
 **/
@Service
public class DictServiceImpl implements DictService {
    @Autowired
    DictService dictService;
    @Autowired
    SysDictDOMapper dictDOMapper;

    @Override
    @Cacheable(value = "dicts_map")
    public Map<String, Map<String, String>> getDictsMap() {
        List<SysDictDO> dictsList = dictDOMapper.listByEntity(new SysDictDO());
        Map<String, Map<String, String>> listMap = Maps.newHashMap();
        for (SysDictDO dict : dictsList) {
            Map<String, String> map = listMap.get(dict.getType());
            if (map == null) {
                map = Maps.newHashMap();
            }
            map.put(dict.getValue(), dict.getName());
            listMap.put(dict.getType(), map);
        }
        return listMap;
    }

    @Override
    public <T extends BaseDO> void setDictName(List<T> list, Class<? extends BaseDO> clazz) {
        Map<String, Map<String, String>> dictsMap = dictService.getDictsMap();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                if (field.getAnnotationsByType(DictName.class).length != 0) {
                    Annotation annotation = field.getAnnotationsByType(DictName.class)[0];
                    String type = ((DictName) annotation).type();
                    Map<String, String> dicts = dictsMap.get(type);
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                    Method rM = pd.getReadMethod();
                    Method wM = pd.getWriteMethod();
                    for (T t : list) {
                        String value = (String) rM.invoke(t);
                        if (dicts != null) {
                            wM.invoke(t, dicts.get(value));
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new BDException("内部错误");
        }
    }

    /**
     * 获取指定type的dict
     *
     * @param type
     * @return
     */
    @Override
    public List<SysDictDO> getDictByType(String type) {
        if (StringUtils.isBlank(type)) {
            return null;
        }
        Map<String, String> map = dictService.getDictsMap().get(type);
        if (null != map && map.size() > 0) {
            List<SysDictDO> list = new ArrayList<>();
            for (String key : map.keySet()) {
                list.add(new SysDictDO(map.get(key), key));
            }
            return list;
        } else {
            return null;
        }
    }

    @Override
    public List<SelectDO> getSelectList(String type) {
        List<SysDictDO> devMap = dictService.getDictByType("dev_type");
        List<SelectDO> list = new ArrayList<>();
        if (!ListUtils.isEmpty(devMap)) {
            devMap.forEach(d -> list.add(new SelectDO(null, d.getName(), d.getValue())));
        }
        return list;
    }

    /**
     * 将值修改回数据字典
     *
     * @param t
     */
    @Override
    public <T> void setNameToDict(T t) {
        if (null != t) {
            Class clz = t.getClass();
            Field[] fields = clz.getDeclaredFields();
            Map<String, Map<String, String>> dictsMap = dictService.getDictsMap();
            for (int i = 0; i < fields.length; i++) {
                Field f = fields[i];
                DictName dictName = f.getAnnotation(DictName.class);
                if (null != dictName) {
                    Map<String, String> valueMap = dictsMap.get(dictName.type());
                    this.resetDictK(f, t, valueMap);
                }
            }
        }
    }

    private <T> void resetDictK(Field f, T t, Map<String, String> valueMap) {
        if (null != valueMap) {
            f.setAccessible(true);
            try {
                Object value = f.get(t);
                if (null != value) {
                    for (Map.Entry<String, String> entry : valueMap.entrySet()) {
                        if (value.toString().equals(entry.getValue())) {
                            f.set(t, entry.getKey());
                            break;
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}
